Skip to content

fix: resolve cross-file discriminator mapping references - #115

Merged
tanmaykm merged 1 commit into
mainfrom
fix/cross-file-discriminator-mapping
Sep 12, 2026
Merged

tanmaykm merged 1 commit into
mainfrom
fix/cross-file-discriminator-mapping

Conversation

@tanmaykm

Copy link
Copy Markdown
Member

Fixes #114.

Problem

Normalization rebases the compiled schema graph onto synthetic portable identifiers. $ref targets survive because the compiler resolves them before the rebase and records them in its reference table. discriminator.mapping and defaultMapping values are not JSON Schema keywords, so the compiler never saw them; planning resolved them lazily after the rebase, against the synthetic base, so any relative or cross-file value failed with invalid_discriminator_mapping. Mapping values were also resolved relative to the union schema rather than the schema that owns the discriminator.

Changes

  • src/schema_engine/compiled.jl: generic extra_references hook on the compiler constructors. It is called with each scanned schema object and returns (pointer, reference) pairs, with the pointer relative to that schema object. Pairs are resolved like $ref, retrieving files as needed, and recorded under the pointer key. They are optional: retrieval or resolution failures land in a new reference_failures table (read through reference_failure) instead of aborting compilation. A retrieved document that fails to compile stays fatal. The engine stays OpenAPI-agnostic.
  • src/schema_engine/rebase.jl: carries bindings and failures across the rebase and rewrites pointer-keyed reference strings in the rebased documents, so serialized specs use only portable ids.
  • src/normalize.jl: declares URI-shaped mapping / defaultMapping values through the hook. Bare names such as Cat are left alone, following the OAS 3.1.1 rule that ambiguous values are schema names and ./Cat forces a URI reference.
  • src/planning.jl: _discriminator_target reads the recorded binding keyed by the discriminator owner's node, reports recorded failures as invalid_discriminator_mapping / invalid_discriminator_default with the retrieval message, and falls back to same-document lookup for values the compiler was not asked about.
  • Docs: models.md, pipeline.md.

Tests

  • Engine: hook resolves local and remote targets, records failures, validates hook output; $ref and broken retrieved documents remain fatal.
  • Rebase: bindings and failures survive rebasing; resolved strings are rewritten to portable ids, unresolved strings left as written.
  • Cross-file discriminators: union in its own file under schemas/, mapping values mixing whole-file, empty-fragment and pointer-fragment targets; generated client decodes all variants and rejects a mismatched body; allOf inheritance layout plans; a typo'd file yields a diagnostic naming the missing file.

Verification

  • Full suite on Julia 1.12 and 1.10.11: pass.
  • OPENAPI_CORPUS_TESTS=all on Julia 1.12 (Petstore, Discord, Stripe, GitHub): pass.
  • git diff --check: clean.

Notes

  • Planning diagnostics for schema nodes report the rebased portable id as location (pre-existing, unchanged).
  • Bare schema-name mapping values (feline: Cat) behave exactly as before; supporting them is a possible follow-up.

`discriminator.mapping` and `defaultMapping` values are URI references
that live outside the JSON Schema vocabulary, so the schema compiler
never saw them. Planning resolved them lazily after the compiled graph
had been rebased onto portable identifiers, so any relative or
cross-file value failed with `invalid_discriminator_mapping` even though
the same URI worked in `$ref`. Mapping values were also resolved
relative to the union schema rather than the schema that owns the
discriminator.

The schema engine gains a generic `extra_references` compilation hook:
callers name additional reference strings inside schema objects, keyed
by a JSON Pointer relative to the schema. They are resolved like `$ref`
before rebasing, retrieving target resources when needed, and recorded
in the reference table. Failures to retrieve or resolve them are
recorded for `reference_failure` instead of aborting compilation;
retrieved documents that fail to compile stay fatal. Rebasing carries
the bindings and failures across and rewrites the resolved strings.

Normalization declares URI-shaped mapping values through the hook (bare
schema names are left alone per OAS 3.1.1), and planning reads the
recorded binding for the discriminator owner's node, reporting recorded
failures as located diagnostics.

Fixes #114
@tanmaykm
tanmaykm merged commit 743cbe4 into main Sep 12, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

invalid_discriminator_mapping error

1 participant